namespace SimpleWebServices.Web.Mvc
{
    using System;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Net;
    using System.Threading;
    using System.Web;
    using System.Web.Mvc;
    using Moq;
    using SimpleWebServices.Configuration;
    using Xunit;

    public sealed class InternalServerErrorAttributeFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<InternalServerErrorAttribute>()
                .DerivesFrom<FilterAttribute>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .Implements<IExceptionFilter>()
                .IsDecoratedWith<AttributeUsageAttribute>()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new InternalServerErrorAttribute());
        }

        [Fact]
        public void op_OnException_ExceptionContextNull()
        {
            Assert.Throws<ArgumentNullException>(() => new InternalServerErrorAttribute().OnException(null));
        }

        [Fact]
        public void op_OnException_ExceptionContext()
        {
            Default.Clear();
            ServiceLocator.Clear();

            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                Default.Register<InternalServerError>("<resource />");

                ServiceLocator.Register<IViewResult, InternalServerErrorViewResult>("InternalServerError");

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<bool>(x => x.IsCustomErrorEnabled).Returns(true).Verifiable();
                mock.SetupGet<string>(x => x.Request.HttpMethod).Returns("GET").Verifiable();
                mock.SetupGet<Uri>(x => x.Request.Url).Returns(new Uri("http://example.com/path?query")).Verifiable();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Accept", "*/*" } }).Verifiable();
                mock.Setup(x => x.Response.Clear()).Verifiable();
                mock.SetupSet(x => x.Response.StatusCode).Callback(actual => Assert.Equal<int>(actual, (int)HttpStatusCode.InternalServerError)).Verifiable();
                mock.Setup(x => x.Response.Cache.SetCacheability(HttpCacheability.NoCache)).Verifiable();
                mock.SetupSet(x => x.Response.TrySkipIisCustomErrors).Callback(actual => Assert.True(actual)).Verifiable();

                ExceptionContext filterContext = new ExceptionContext
                {
                    HttpContext = mock.Object,
                    Exception = new HttpException(),
                    ExceptionHandled = false
                };

                new InternalServerErrorAttribute().OnException(filterContext);

                Assert.True(filterContext.ExceptionHandled);
                Assert.IsAssignableFrom<InternalServerErrorViewResult>(filterContext.Result);

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                Default.Reset();
                ServiceLocator.Reset();
            }
        }
    }
}